﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;
using System.Windows.Forms;
using Spider.Entity;
using System.Net;
using System.Configuration;
using Spider.Ex;
using System.Text.RegularExpressions;

namespace Spider.Spider
{
    public delegate void SpiderCompletedEventHandler(object sender, SpiderEventArgs e);

    public abstract class SpiderBase
    {
        //爬虫工作完成事件
        public event SpiderCompletedEventHandler SpiderCompleted;

        //最终结果集
        private Dictionary<string, string> _uriTotal = null;

        //当前正在运行的线程数
        private int _threadCount = 0;

        object o = new object();

        public SpiderBase()
        {
            Initialization();
        }

        private List<UriConfig> _config;
        public List<UriConfig> Config
        {
            set { _config = value; }
        }

        private string _siteName;
        public string SiteName
        {
            set { _siteName = value; }
        }

        private void Initialization()
        {
            _uriTotal = new Dictionary<string, string>();
        }

        protected void OnSpiderCompleted(SpiderEventArgs e)
        {
            if (SpiderCompleted != null)
                SpiderCompleted(this, e);
        }


        public void Run()
        {
            _threadCount = _config.Sum(p => p.ThreadCount);

            foreach (UriConfig item in _config)
            {
                if (item.ThreadCount <= 0) continue;

                Dictionary<int, Thread> threads = new Dictionary<int, Thread>();

                for (int i = 0; i < item.ThreadCount; i++)
                {
                    ThreadStart threadStart = delegate { SpiderTask(i, item); };
                    Thread thread = new Thread(threadStart);
                    thread.Start();
                    //主线程挂起50毫秒，因为启动线程需要时间，会打乱循环的i值
                    System.Threading.Thread.Sleep(50);
                }
            }
        }

        private void SpiderTask(int i, UriConfig config)
        {
            int m = Math.Abs(config.PageCount / config.ThreadCount);

            int pageBegin = config.PageIndex + i * m;
            int pageEnd = pageBegin + m - 1;

            for (int j = pageBegin; j <= pageEnd; j++)
            {
                string pageUri = PageUriFormat(config.PageUri, j);

                Parse(config.Uri, config.City, pageUri, config.Rule, config.Parser, ref _uriTotal);
            }

            lock (o)
            {
                _threadCount--;
                //所有线程跑完终止爬虫工作
                if (_threadCount <= 0)
                {
                    SpiderEventArgs e = new SpiderEventArgs(_siteName, _uriTotal);
                    OnSpiderCompleted(e);
                    return;
                }
            }
        }

        protected virtual string PageUriFormat(string pageUri, int pageIndex)
        {
            return string.Format(pageUri, pageIndex);
        }

        protected abstract string Format(string webSite, string matchUri);

        private void Parse(string webSite, string city, string pageUri, string reg, string parser, ref Dictionary<string, string> result)
        {
            WebClient client = new WebClient();
            Proxy(client);
            byte[] buffer = client.DownloadData(pageUri);
            string content = System.Text.Encoding.UTF8.GetString(buffer);

            Regex regex = new Regex(reg);
            MatchCollection matches = regex.Matches(content);

            IEnumerator enu = matches.GetEnumerator();
            while (enu.MoveNext() && enu.Current != null)
            {
                Match match = (Match)(enu.Current);
                if (!result.ContainsKey(Format(webSite, match.Value)))
                    result.Add(Format(webSite, match.Value), city + ":" + parser);
            }
        }

        //private void Parse(string webSite, string city, string pageUri, string reg, string parser, ref Dictionary<string, string> result)
        //{


        //    WebClient client = new WebClient();
        //    Proxy(client);
        //    byte[] buffer = client.DownloadData(pageUri.Replace("||", "&"));
        //    string content = System.Text.Encoding.UTF8.GetString(buffer);
        //    string reg1 = @"(?<a>(?<=href="")/file/file_viewfile.php.*(?="">))"">(?<b>.+(?=</a>))";

        //    Regex regex = new Regex(reg1);
        //    MatchCollection matches = regex.Matches(content);

        //    IEnumerator enu = matches.GetEnumerator();
        //    while (enu.MoveNext() && enu.Current != null)
        //    {
        //        Match match = (Match)(enu.Current);
        //        var a = match.Groups["a"].Value;
        //        var b = match.Groups["b"].Value;
                
        //        result.Add(Guid.NewGuid().ToString(), b);
        //    }
        //}

        private void Proxy(WebClient client)
        {
            string proxy = ConfigurationSettings.AppSettings["Proxy"];
            if (!string.IsNullOrEmpty(proxy))
            {
                WebProxy webProxy = new WebProxy(proxy.Split(':')[0], proxy.Split(':')[1].TryInt());
                webProxy.UseDefaultCredentials = true;
                client.Proxy = webProxy;
            }
        }
    }

    public class SpiderEventArgs : EventArgs
    {
        private Dictionary<string, string> _uris = null;

        private string _siteName = "";

        public SpiderEventArgs(string siteName, Dictionary<string, string> uris)
        {
            _uris = uris;
            _siteName = siteName;
        }

        public string SiteName
        {
            get { return _siteName; }
        }

        public Dictionary<string, string> Uris
        {
            get { return _uris; }
        }
    }
}
